#include "kbdev.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <poll.h>
#include <time.h>
#include <stdbool.h>
#include "DemoActions.h"

//=======================================================================//
//= Static variable declaration                                        =//
//=======================================================================//
static int s_kb_fd = -1;

// 按键去抖相关变量
#define DEBOUNCE_TIME_MS    50  // 去抖时间20毫秒

typedef struct {
    int keycode;
    int last_value;
    struct timespec last_time;
    bool initialized;
} KEY_DEBOUNCE_INFO;

static KEY_DEBOUNCE_INFO s_debounce_info = {0, 0, {0, 0}, false};

//=======================================================================//
//= Static function declaration                                        =//
//=======================================================================//
static bool KBDEV_DebounceKey(int keycode, int value, struct timespec event_time);
static unsigned long KBDEV_TimeDiffMs(struct timespec start, struct timespec end);

//=======================================================================//
//= Function definition                                                =//
//=======================================================================//

/*****************************************************************************/
/** Function Name:  KBDEV_TimeDiffMs                                        **/
/** Purpose:        Calculate time difference in milliseconds               **/
/** Parameters:                                                             **/
/** @ start[in]:    Start time                                              **/
/** @ end[in]:      End time                                                **/
/** Return:         Time difference in milliseconds                         **/
/*****************************************************************************/
static unsigned long KBDEV_TimeDiffMs(struct timespec start, struct timespec end)
{
    unsigned long diff_sec = end.tv_sec - start.tv_sec;
    long diff_nsec = end.tv_nsec - start.tv_nsec;
    
    if (diff_nsec < 0) {
        diff_sec--;
        diff_nsec += 1000000000L;
    }
    
    return (diff_sec * 1000) + (diff_nsec / 1000000);
}

/*****************************************************************************/
/** Function Name:  KBDEV_DebounceKey                                       **/
/** Purpose:        Debounce key events                                     **/
/** Parameters:                                                             **/
/** @ keycode[in]:  Key code                                                **/
/** @ value[in]:    Key event value (0=release, 1=press, 2=repeat)          **/
/** @ event_time[in]: Event timestamp                                       **/
/** Return:         true if event should be processed, false if filtered    **/
/*****************************************************************************/

#if 0
static bool KBDEV_DebounceKey(int keycode, int value, struct timespec event_time)
{
    // 如果是新按键或者按键状态改变
    if (!s_debounce_info.initialized || s_debounce_info.keycode != keycode) {
        // 初始化按键信息
        s_debounce_info.keycode = keycode;
        s_debounce_info.last_value = value;
        s_debounce_info.last_time = event_time;
        s_debounce_info.initialized = true;
        return true;
    }
    
    // 如果按键状态没有改变，检查时间间隔
    if (s_debounce_info.last_value == value) {
        unsigned long time_diff = KBDEV_TimeDiffMs(s_debounce_info.last_time, event_time);
        
        // 如果时间间隔小于去抖时间，则过滤掉该事件
        if (time_diff < DEBOUNCE_TIME_MS) {
            return false;
        }
    }
    
    // 更新按键状态和时间
    s_debounce_info.last_value = value;
    s_debounce_info.last_time = event_time;
    
    return true;
}
#endif
/*****************************************************************************/
/** Function Name:  KBDEV_DebounceKey                                       **/
/** Purpose:        Debounce key events                                     **/
/** Parameters:                                                             **/
/** @ keycode[in]:  Key code                                                **/
/** @ value[in]:    Key event value (0=press, 1=release)                    **/
/** @ event_time[in]: Event timestamp                                       **/
/** Return:         true if event should be processed, false if filtered    **/
/*****************************************************************************/
static bool KBDEV_DebounceKey(int keycode, int value, struct timespec event_time)
{
    // 对于按键释放事件(1)，重置去抖动状态
    if (value == 1) 
    {
        if (s_debounce_info.initialized && s_debounce_info.keycode == keycode) 
        {
            // 只有当释放的是当前跟踪的按键时才重置
            s_debounce_info.initialized = false;
        }
       return true; // 总是允许释放事件通过
    }
    
    // 对于按键按下事件(0)
    if (!s_debounce_info.initialized || s_debounce_info.keycode != keycode) 
    {
        // 新按键或不同按键，初始化去抖动信息
        s_debounce_info.keycode = keycode;
        s_debounce_info.last_value = value;
        s_debounce_info.last_time = event_time;
        s_debounce_info.initialized = true;
        return true; // 允许首次按下事件通过
    }
    
    // 相同按键再次按下，检查时间间隔
    unsigned long time_diff = KBDEV_TimeDiffMs(s_debounce_info.last_time, event_time);
    printf("%d keycode=%d keytime=%d:%d--%d:%d\n", __LINE__, keycode,event_time.tv_sec, event_time.tv_nsec, 
                           s_debounce_info.last_time.tv_sec, s_debounce_info.last_time.tv_nsec);
    
    // 如果时间间隔足够长，允许事件通过
    if (time_diff >= DEBOUNCE_TIME_MS) 
    {
        s_debounce_info.last_value = value;
        s_debounce_info.last_time = event_time;
        return true;
    }
    
    // 时间间隔太短，过滤掉该事件
    return false;
}

/*****************************************************************************/
/** Function Name:  KBDEV_Initialize                                        **/
/** Purpose:        Initialize keyboard device                              **/
/** Parameters:     None                                                    **/
/** Return:         0 on success, -1 on failure                             **/
/*****************************************************************************/
int KBDEV_Initialize(void)
{
    /* Close if already opened */
    if (s_kb_fd >= 0) {
        close(s_kb_fd);
        s_kb_fd = -1;
    }
    
    /* Open input device */
    s_kb_fd = open(EVKEYB_NAME, O_RDONLY | O_NONBLOCK);
    if (s_kb_fd < 0) {
        printf("Failed to open %s: %s\n", EVKEYB_NAME, strerror(errno));
        return -1;
    }
    
    /* Reset debounce info */
    s_debounce_info.initialized = false;
    
    #ifdef DEBUG_KBDEV
    char name[256] = "Unknown";
    if (ioctl(s_kb_fd, EVIOCGNAME(sizeof(name)), name) >= 0) {
        printf("Opened keyboard device: %s\n", name);
    }
    #endif
    
    return 0;
}

/*****************************************************************************/
/** Function Name:  KBDEV_ReadKey                                           **/
/** Purpose:        Read key event from keyboard device                     **/
/** Parameters:                                                             **/
/** @ pstKeyInfo[out]: Pointer to store key information                     **/
/** Return:         1 if key event available, 0 if no event, -1 on error    **/
/*****************************************************************************/
int KBDEV_ReadKey(KBDEV_KEY_INFO* pstKeyInfo)
{
    struct input_event ev;
    ssize_t bytes;
    
    /* Check parameters */
    if (s_kb_fd < 0 || pstKeyInfo == NULL) {
        return -1;
    }
    
    /* Non-blocking read */
    bytes = read(s_kb_fd, &ev, sizeof(struct input_event));
    if (bytes < 0) 
    {
        if (errno == EAGAIN || errno == EWOULDBLOCK) 
        {
            /* No data available */
            return 0;
        } 
        else 
        {
            /* Real error */
            printf("Error reading from keyboard device: %s\n", strerror(errno));
            return -1;
        }
    }
    
    if (bytes != sizeof(struct input_event)) 
    {
        printf("Incomplete event data read\n");
        return -1;
    }
    
    /* Check if it's a key event */
    if (ev.type == EV_KEY) 
    {
        struct timespec event_time;
        event_time.tv_sec = ev.time.tv_sec;
        event_time.tv_nsec = ev.time.tv_usec * 1000;
        // 按键去抖处理
        if (!KBDEV_DebounceKey(ev.code, ev.value, event_time)) 
        {
            #ifdef DEBUG_KBDEV
            printf("a Key event filtered by debounce: code=%d, value=%d\n", ev.code, ev.value);
            #endif
            return 0;  // 过滤掉抖动事件
        }
        
        pstKeyInfo->iEventType = ev.value;
        pstKeyInfo->uiKeyValue = KBDEV_TranslateKeyCode(ev.code, ev.value);
        
        #ifdef DEBUG_KBDEV
        printf("Key event passed debounce: code=%d, value=%d, keyValue=0x%X\n", 
               ev.code, ev.value, pstKeyInfo->uiKeyValue);
        #endif
        
        return 1;  // Key event available
    }
    
    return 0;  // Not a key event
}

/*****************************************************************************/
/** Function Name:  KBDEV_ReadKey_Timeout                                   **/
/** Purpose:        Read key event from keyboard device with timeout        **/
/** Parameters:                                                             **/
/** @ pstKeyInfo[out]: Pointer to store key information                     **/
/** Return:         1 if key event available, 0 if no event, -1 on error    **/
/*****************************************************************************/
int KBDEV_ReadKey_Timeout(KBDEV_KEY_INFO* pstKeyInfo)
{
    fd_set readfds;
    struct timeval timeout;
    struct input_event ev;
    ssize_t bytes;
    
    /* Check parameters */
    if (s_kb_fd < 0 || pstKeyInfo == NULL) {
        return -1;
    }
    
    /* Initialize file descriptor set */
    FD_ZERO(&readfds);
    FD_SET(s_kb_fd, &readfds);
    
    /* Set timeout to 50ms */
    timeout.tv_sec = 1;
    timeout.tv_usec = 50000;  // 50ms = 50000 microseconds
    
    /* Use select to wait for data with timeout */
    int result = select(s_kb_fd + 1, &readfds, NULL, NULL, &timeout);
    
    if (result < 0) 
    {
        /* Error occurred */
        printf("Error in select: %s\n", strerror(errno));
        return -1;
    } else if (result == 0) 
    {
        /* Timeout - no data available within 50ms */
        return 0;
    }
    
    /* Data is available, read the event */
    if (FD_ISSET(s_kb_fd, &readfds)) {
        bytes = read(s_kb_fd, &ev, sizeof(struct input_event));
        if (bytes < 0) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                /* No data available */
                return 0;
            } else {
                /* Real error */
                printf("Error reading from keyboard device: %s\n", strerror(errno));
                return -1;
            }
        }
        
        if (bytes != sizeof(struct input_event)) {
            printf("Incomplete event data read\n");
            return -1;
        }
        
        /* Check if it's a key event */
        if (ev.type == EV_KEY) 
        {
            // 按键去抖处理
            struct timespec event_time;
            event_time.tv_sec = ev.time.tv_sec;
            event_time.tv_nsec = ev.time.tv_usec * 1000;
            if (!KBDEV_DebounceKey(ev.code, ev.value, event_time)) 
            {  
                //printf("b Key event filtered by debounce: code=%d, value=%d\n", ev.code, ev.value);
                return 0;  // 过滤掉抖动事件
            }else
            {
               // printf("c Key event filtered by debounce: code=%d, value=%d\n", ev.code, ev.value);   
            }
            
            pstKeyInfo->iEventType = ev.value;
            pstKeyInfo->uiKeyValue = KBDEV_TranslateKeyCode(ev.code, ev.value);
            
            #ifdef DEBUG_KBDEV
            printf("Key event passed debounce: code=%d, value=%d, keyValue=0x%X\n", 
                   ev.code, ev.value, pstKeyInfo->uiKeyValue);
            #endif
            
            return 1;  // Key event available
        }
    }
    
    return 0;  // Not a key event
}

/*****************************************************************************/
/** Function Name:  KBDEV_PollEvent                                        **/
/** Purpose:        Check if there is key event available                   **/
/** Parameters:                                                             **/
/** @ iTimeoutMS[in]: Timeout in milliseconds (0 = non-blocking)            **/
/** Return:         1 if event available, 0 if timeout, -1 on error         **/
/*****************************************************************************/
int KBDEV_PollEvent(int iTimeoutMS)
{
    struct pollfd pfd;
    
    if (s_kb_fd < 0) {
        return -1;
    }
    
    pfd.fd = s_kb_fd;
    pfd.events = POLLIN;
    
    return poll(&pfd, 1, iTimeoutMS);
}

/*****************************************************************************/
/** Function Name:  KBDEV_TranslateKeyCode                                 **/
/** Purpose:        Translate raw key code to application key value         **/
/** Parameters:                                                             **/
/** @ iKeyCode[in]: Raw key code from input event                           **/
/** @ iEventType[in]: Key event type                                        **/
/** Return:         Translated key value                                    **/
/*****************************************************************************/
unsigned int KBDEV_TranslateKeyCode(int iKeyCode, int iEventType)
{
    /* Only process key press events (value = 1) */
    if (iEventType != 0) {
        return 0;  // Invalid key or release/repeat event
    }

    printf("KBDEV_TranslateKeyCode keycode=%d\n", iKeyCode);
    
    /* Translate key codes based on standard keyboard codes */
    switch (iKeyCode) 
    {
        case KEY_UP:        // Usually 103
            return KEY_VALUE_UP;  // Up key code
        case KEY_DOWN:      // Usually 108
            return KEY_VALUE_DOWN;  // Down key code
        case KEY_ENTER:     // Usually 28
            return KEY_VALUE_ENTER;  // Enter key code
        case KEY_ESC:       // Usually 1
            return KEY_VALUE_ESC;  // ESC key code
        case KEY_LEFT:      // Usually 105
            return KEY_VALUE_LEFT;  // Left key code (can be same as Enter or different)
        case KEY_RIGHT:     // Usually 106
            return KEY_VALUE_RIGHT;  // Right key code
        case KEY_SPACE:     // Usually 57
            return KEY_VALUE_SPACE;  // Space key code
        case KEY_VALUE_MENU:
            return KEY_VALUE_MENU;
        case KEY_VALUE_PAUSE:
            return KEY_VALUE_PAUSE;
        case KEY_VALUE_LIGHT:
            return KEY_VALUE_LIGHT;
        case KEY_VALUE_SHUTDOWN:
            return KEY_VALUE_SHUTDOWN;
        default:
            #ifdef DEBUG_KBDEV
            printf("Unhandled key code: %d\n", iKeyCode);
            #endif
            return 0;       // Unknown key
    }
}

/*****************************************************************************/
/** Function Name:  KBDEV_Close                                             **/
/** Purpose:        Close keyboard device                                   **/
/** Parameters:     None                                                    **/
/** Return:         None                                                    **/
/*****************************************************************************/
void KBDEV_Close(void)
{
    if (s_kb_fd >= 0) {
        close(s_kb_fd);
        s_kb_fd = -1;
    }
    
    // Reset debounce info
    s_debounce_info.initialized = false;
}